package com.nantong.admin.service.impl;

import java.time.Duration;
import java.util.Date;
import java.util.Set;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import com.nantong.admin.domain.SysUser;
import com.nantong.admin.domain.dto.LoginDTO;
import com.nantong.admin.domain.dto.LoginResultDTO;
import com.nantong.admin.service.ISysAuthService;
import com.nantong.admin.service.ISysPermissionService;
import com.nantong.admin.service.ISysRoleService;
import com.nantong.admin.service.ISysUserService;
import com.nantong.admin.util.LoginHelper;
import com.nantong.common.core.constant.Constants;
import com.nantong.common.core.domain.model.LoginUser;
import com.nantong.common.core.enums.commonEnums.StatusEnum;
import com.nantong.common.core.enums.commonEnums.UserType;
import com.nantong.common.core.exception.ServiceException;
import com.nantong.common.core.utils.StringUtils;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * 认证授权 业务层处理
 *
 * @author nantong
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysAuthServiceImpl implements ISysAuthService {

    private final ISysUserService userService;
    private final ISysRoleService roleService;
    private final ISysPermissionService permissionService;

    @Override
    public LoginResultDTO login(LoginDTO loginDTO) {
        // 校验参数
        if (StringUtils.isEmpty(loginDTO.getUsername()) || StringUtils.isEmpty(loginDTO.getPassword())) {
            throw new ServiceException("用户名和密码不能为空");
        }

        // 查询用户
        SysUser user = userService.selectUserByUserName(loginDTO.getUsername());
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", loginDTO.getUsername());
            throw new ServiceException("用户不存在/密码错误");
        }

        // 校验用户状态
        if (StatusEnum.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", loginDTO.getUsername());
            throw new ServiceException("对不起，您的账号：" + loginDTO.getUsername() + " 已停用");
        }

        // 校验密码
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            log.info("登录用户：{} 密码错误.", loginDTO.getUsername());
            throw new ServiceException("用户不存在/密码错误");
        }

        // 构建登录用户信息
        LoginUser loginUser = buildLoginUser(user);

        // 获取用户角色和权限
        Set<String> roleKeys = roleService.selectRoleKeysByUserId(user.getUserId());
        Set<String> permissionKeys = permissionService.listPermissionKeysByUserId(user.getUserId());
        loginUser.setRolePermission(roleKeys);
        loginUser.setMenuPermission(permissionKeys);

        // 生成token
        SaLoginParameter model = new SaLoginParameter();
        // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
        // 例如: 后台用户30分钟过期 app用户1天过期
        model.setTimeout(30 * 60 * 60);
        model.setActiveTimeout(30 * 60 * 60);
        LoginHelper.login(loginUser, model);
        String tokenValue = StpUtil.getTokenValue();
        // 更新用户登录信息
        updateUserLoginInfo(user);

        // 构建返回结果
        LoginResultDTO result = new LoginResultDTO();
        result.setAccessToken(tokenValue);
        result.setExpiresIn(StpUtil.getTokenTimeout());

        LoginResultDTO.UserInfoDTO userInfo = new LoginResultDTO.UserInfoDTO();
        userInfo.setUserId(user.getUserId());
        userInfo.setUsername(user.getUserName());
        userInfo.setNickname(user.getNickName());
        userInfo.setAvatar(user.getAvatar());
        userInfo.setEmail(user.getEmail());
        userInfo.setPhonenumber(user.getPhonenumber());
        result.setUserInfo(userInfo);

        log.info("用户：{} 登录成功", loginDTO.getUsername());
        return result;
    }

    @Override
    public LoginUser getLoginUser() {
        return getLoginUser(StpUtil.getTokenValue());
    }

    @Override
    public LoginUser getLoginUser(String token) {
        if (StrUtil.isBlank(token)) {
            return null;
        }
        try {
            // 根据token获取登录用户信息
            Object loginUserObj = StpUtil.getSessionByLoginId(StpUtil.getLoginIdByToken(token))
                    .get(Constants.LOGIN_USER_KEY);
            if (ObjectUtil.isNotNull(loginUserObj)) {
                return (LoginUser) loginUserObj;
            }
        } catch (Exception e) {
            log.error("获取用户信息异常'{}'", e.getMessage());
        }
        return null;
    }

    @Override
    public void refreshToken(LoginUser loginUser) {
        // 刷新token有效期
        StpUtil.renewTimeout(Duration.ofDays(7).getSeconds());
    }

    @Override
    public void logout() {
        logout(StpUtil.getTokenValue());
    }

    @Override
    public void logout(String token) {
        if (StrUtil.isNotBlank(token)) {
            try {
                StpUtil.logoutByTokenValue(token);
            } catch (Exception e) {
                log.error("用户登出异常'{}'", e.getMessage());
            }
        }
    }

    /**
     * 构建登录用户信息
     */
    private LoginUser buildLoginUser(SysUser user) {
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getUserId());
        loginUser.setUsername(user.getUserName());
        loginUser.setNickname(user.getNickName());
        loginUser.setUserType(UserType.SYS_USER.getCode());
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(System.currentTimeMillis() + Duration.ofDays(7).toMillis());
        loginUser.setIpaddr("127.0.0.1"); // 这里可以从请求中获取真实IP
        return loginUser;
    }

    /**
     * 更新用户登录信息
     */
    private void updateUserLoginInfo(SysUser user) {
        user.setLoginIp("127.0.0.1"); // 这里可以从请求中获取真实IP
        user.setLoginDate(new Date());
        userService.updateById(user);
    }

}
